在原生裏面,要偵測螢幕尺寸可以使用 window
,在 Vue 的 <script>
裡面也可以使用 window
的屬性 innerWidth
, innerHeight
。
但如果在 Vue檔的 <template>
寫上 {{ window }}
會顯示: "[object Window]"
在 <template>
是拿不到 window
的,除非在 main.js
裏面新增:
app.config.globalProperties.window = window;
就可以在 <template>
使用 window 的屬性了。
然而這個只能拿到當下的螢幕尺寸大小,如果有人在那邊拉來拉去(就是你們這些前端仔!),讓網頁的寬度改變的話,window
是無法偵測到的。
如果今天要在螢幕在 576px 以上讓 element 的 class 新增一個改變容器置中的功能,該怎麼做到 即時偵測螢幕寬度 呢?
以下會介紹使用 VueUse 跟 使用原生的用法:
ref()
直接用 npm install 安裝到專案中:
npm i @vueuse/core
裏面有非常多的函式可以被 use,找到一個最符合要偵測螢幕尺寸大小的。
安裝之後,就可以直接使用 width
, height
了。
import { useWindowSize } from '@vueuse/core'
const { width, height } = useWindowSize()
接著再使用 Vue 的 watch
就可以及時偵測目前螢幕變化的大小~
const isCentered = ref(null);
watch(width, (newWidth, oldWidth) => {
if (newWidth >= 576) {
isCentered.value = true;
} else {
isCentered.value = false;
}
});
於是在 <template>
也可以使用這個響應式變化了!
在 576px 以上會自動新增 modal-dialog-centered
class名稱上去,其他 size 則自動沒有。
<div
class="modal-dialog modal-fullscreen-sm-down modal-lg"
:class="{ 'modal-dialog-centered': isCentered }"
>
好奇去看了一下 useWindowSize的原始碼,發現 useWindowSize
吃的是 resize
事件的呢
useEventListener('resize', update, { passive: true })
他只會在有改變螢幕大小時觸發,如果在一進去頁面就不會有任何改變,如果還要為一開始進來偵測螢幕大小給不同狀態的話,還是先得用 window
去抓當下的螢幕尺寸,然後剩下就給調整大小時,才有 watch
的改變!
在寫鐵人賽的當下我只會使用 computed, watch,不過後來學習到 watchEffect 發現更適合。以下會介紹兩種不同的寫法。
雖然我使用了 VueUse 做到這件事,但因為當初沒有想到可以使用 resize 事件來偵測,所以又用原生試試看,發現也可以啊 XD
onMounted()
裡面放一個 window.addEventListener('resize')
let windowWidth = ref(window.innerWidth);
windowWidth
,這樣只要 windowWidth
改變,這個 computed 就會去計算<template>
放上 computed 的變數就好了!const resizeFont = ref("");
const isLess500 = ref(false);
const isBigger500 = ref(false);
let windowWidth = ref(window.innerWidth);
const resize = computed(() => {
return windowWidth;
});
onMounted(() => {
window.addEventListener("resize", function () {
windowWidth.value = window.innerWidth;
if (windowWidth.value < 500) {
resizeFont.value = "less than 500px";
isLess500.value = true;
isBigger500.value = false;
} else {
resizeFont.value = "greater than 500px";
isBigger500.value = true;
isLess500.value = false;
}
});
});
再試著在resize的時候去改文字顏色也有成功
<span>window.innerWidth : </span>
<span>{{ resize }}</span>
<p :class="{ changeResizeColor: isLess500, blue: isBigger500 }">
{{ resizeFont }}
</p>
成果:
因為其實我們需要第一次的值,這樣使用 watchEffect 的話,第一次就算沒有 resize 但還是會有初始值
watchEffect 沒有 oldValue, newValue 直接給一個 callback , watch 會自動建立 callback 裡面的變數來產生依賴。
window.innerWidth
賦值給響應式變數 windowWidth
const result1 = ref("");
onMounted(() => {
window.addEventListener("resize", function () {
windowWidth.value = window.innerWidth;
});
});
// window width
const windowWidth = ref(window.innerWidth);
watchEffect(() => {
if (windowWidth.value < 300) {
result1.value = "its less than 300px";
} else {
result1.value = "its greatter than 300px";
}
});
程式碼變很少吧!
成果:
onMounted()
裏面用 VueUse + watch 比較快,但是對於新手來說有點困難(我),感覺就是誤打誤撞XD
如果還有更好的方法請推薦給我吧~歐內該~
怎麼會突然就進到Vue
了呢XD
剩下一個禮拜了~~~~
參考資料:
VueUse
Vue js 3 - watch window.innerWidth does not working
Day_24: 讓 Vite 來開啟你的Vue 之 VueUse
Vanilla JS 與 Vue 的生命週期 Day 28
Add support for a v-on:resize event #1915